package jfprincesstests.graphsupport;

import laboratoryQ.junit.ignore.patch.BaseTestCase;
import laboratoryQ.computation.BaseUtils;
import puntaelena.graphsupport.solver.IFacilityLocationSolver;
import puntaelena.graphsupport.*;

public class TestGraphGenerate extends BaseTestCase {
	public void testGraphGenerate() {
		int expectedNeighbors = 12;
		int firstBipart = 200;
		int secondBipart = 100;
		int vertCount = firstBipart + secondBipart;

		IGraphGenerator generator = GraphSupportFront.expensiveCheapGenerator();
		GenerateGrSettings grSettings = new GenerateGrSettings(firstBipart, secondBipart);
		grSettings.neighborCountBeg = expectedNeighbors;
		grSettings.neighborCountRange = 3;
		grSettings.cheapEdgeBeg = 100;
		grSettings.cheapEdgeRange = 1;
		grSettings.expensiveEdgeBeg = 700;
		grSettings.expensiveEdgeRange = 1;
		grSettings.facilityPriceBeg = 300;
		grSettings.facilityPriceRange = 1;
		Graph graph = generator.generate(grSettings);
		assertEquals(vertCount, graph.getVertexCount());

		for (int i = 0; i < vertCount; i++) {
			int neighborsCount = 0;
			for (int j = 0; j < vertCount; j++) {
				if ((i < firstBipart) == (j < firstBipart)) { // from dif biparts
					assertFalse(graph.existsEdge(i, j));
				}
				if (graph.existsEdge(i, j)) {
					neighborsCount++;
				}
			}
			if (i < firstBipart) {
				assertTrue(neighborsCount > expectedNeighbors * 0.7);
				assertTrue(neighborsCount < (expectedNeighbors + 3 ) * 1.1);
			}
		}

		for (int i = 0; i < vertCount; i++) {
			for (int j = 0; j < vertCount; j++) {
				assertEquals(graph.existsEdge(i, j), graph.existsEdge(j, i));
			}
		}

		assertIsInstance(graph, FacilitiesGraph.class);
		FacilitiesGraph fgraph = (FacilitiesGraph)graph;
		assertEquals(secondBipart, fgraph.getFacilitiesPrices().length);
		for (int i = 0; i < secondBipart; i++) {
			assertTrue(fgraph.getFacilitiesPrices()[i] > 0.0);
			assertTrue(fgraph.getFacilitiesPrices()[i] < fgraph.getInfPrice());
		}

		graph = generator.generate(new GenerateGrSettings(123, 456));
		assertEquals(123 + 456, graph.getVertexCount());

		BaseUtils.dispose(generator);
	}

	public void testFacilitiesLocationSolver() {
		IGraphGenerator generator = GraphSupportFront.expensiveCheapGenerator();
		int citiecCount = 100;
		int facilitiesCount = 11;
		Graph graph = generator.generate(new GenerateGrSettings(citiecCount, facilitiesCount));

		IFacilityLocationSolver solverBin = GraphSupportFront.getBinarySolver();
		FacilitiesGraph fgraph = (FacilitiesGraph)graph;

		boolean[] isfcltOpen = new boolean[facilitiesCount];
		int[] witnesses = new int[citiecCount];
		solverBin.solve(fgraph, isfcltOpen, witnesses); // TODO: test fail

		for (int i = 0; i < citiecCount; i++) {
			int witness = witnesses[i];
			assertTrue(witness > -1);
			assertTrue(isfcltOpen[witness]);
		}
		double costBinSearch = GraphSupportFront.computeFacilityLocationCost(fgraph, isfcltOpen, witnesses);
		assertTrue(costBinSearch < fgraph.getInfPrice());

		IFacilityLocationSolver solverTriv = GraphSupportFront.getTrivialSolver();
		solverTriv.solve(fgraph, isfcltOpen, witnesses);
		double costTrivSearch = GraphSupportFront.computeFacilityLocationCost(fgraph, isfcltOpen, witnesses);
		assertTrue(witnesses[0] > -1);
		assertEquals(costBinSearch, costTrivSearch);// TODO: should be costBinSearch < costTrivSearch

		BaseUtils.dispose(generator, solverBin, solverTriv);
	}

	public void testNeighborCount() {
		IGraphGenerator generator = GraphSupportFront.expensiveCheapGenerator();
		GenerateGrSettings settings = new GenerateGrSettings();
		settings.firstBipart = 100;
		settings.secondBipart = 100;
		settings.neighborCountBeg = 20;
		settings.neighborCountRange = 1;

		Graph graph = generator.generate(settings);
		for (int i = 0; i < settings.firstBipart; i++) {
			int ngh = 0;
			for (int j = 0; j < settings.secondBipart; j++) {
				if (graph.existsEdge(i, j + settings.firstBipart)) {
					ngh++;
				}
			}
			assertTrue(ngh > settings.neighborCountBeg * 0.7);
			assertTrue(ngh < settings.neighborCountBeg * 1.1);
		}

		settings.neighborCountBeg = 50;
		graph = generator.generate(settings);
		for (int i = 0; i < settings.firstBipart; i++) {
			int ngh = 0;
			for (int j = 0; j < settings.secondBipart; j++) {
				if (graph.existsEdge(i, j + settings.firstBipart)) {
					ngh++;
				}
			}
			assertTrue(ngh > settings.neighborCountBeg * 0.6);
			assertTrue(ngh < settings.neighborCountBeg * 1.1);
		}
		BaseUtils.dispose(generator);
	}

	public void testTriangleIneq() {
		GenerateGrSettings settings = new GenerateGrSettings(100, 50);
		settings.cheapEdgeBeg = 100;
		settings.cheapEdgeRange = 50;
		settings.expensiveEdgeBeg = 200;
		settings.expensiveEdgeRange = 100;

		IGraphGenerator generator = GraphSupportFront.expensiveCheapGenerator();
		FacilitiesGraph fgraphA = (FacilitiesGraph) generator.generate(settings);
		int triangleIneqConflA = 0;
		double[][] adjMatrixArr = fgraphA.getAdjacentMatrixArr();
		for (int i = 0; i < settings.vertexCount; i++) {
			for (int j = 0; j < settings.vertexCount; j++) {
				double dir = adjMatrixArr[i][j];
				for (int k = 0; k < settings.vertexCount; k++) {
					double sum = adjMatrixArr[i][k] + adjMatrixArr[k][j];
					if (dir > sum) {
						triangleIneqConflA++;
					}
				}
			}
		}
		assertTrue(triangleIneqConflA > 0);

		settings.triangleIneqEnabled = true;
		FacilitiesGraph fgraphB = (FacilitiesGraph) generator.generate(settings);
		int triangleIneqConflB = 0;
		adjMatrixArr = fgraphB.getAdjacentMatrixArr();
		for (int i = 0; i < settings.vertexCount; i++) {
			for (int j = 0; j < settings.vertexCount; j++) {
				double dir = adjMatrixArr[i][j];
				for (int k = 0; k < settings.vertexCount; k++) {
					double sum = adjMatrixArr[i][k] + adjMatrixArr[k][j];
					if (dir > sum) {
						triangleIneqConflB++;
					}
				}
			}
		}
		assertTrue(triangleIneqConflB == 0);

		BaseUtils.dispose(generator);
	}
}
